#-*- coding: utf8 -*-
from tutor.scripts import *
from tutor.plugins.sympy import *

# Limites diversos com resultados entre 0 e 6 (ou não existe).
# Este exercício permite obter questões que testam 6 tipos de habilidades 
# importantes no cálculo de limites (ou na prova da inexistência dos mesmos).
# Para que obtenha uma chance de approx. 10% de que não exista nenhuma habilidade
# descoberta, seria necessário fazer em torno de 13 exercícios.


class Opts:
    @classmethod
    def opt1(cls):
        # Limite existe: prova por fatoração de termos
        a = One * oneof(1, 2, 3) * oneof(-1, 1)
        cb = [0, One * oneof(Half, 1, 3 * Half, 2, 3) * oneof(-1, 1)]
        shuffle(cb)
        c, b = cb
        d = One * oneof(0, 1, 2, 3, 4, 5, 6)
        denom = y - a * x
        numer = (denom * (b * y + c * x + d)).expand()
        func = numer / denom
        point = (0, 0)
        answer = d

        assert len(numer.args) == 4
        return locals()

    @classmethod
    def opt2(cls):
        # Limite não existe: teste por caminhos retos
        numer = oneof(x * oneof(sin, tan)(y), y * oneof(sin, tan)(x))
        denom = oneof(x ** 2 + oneof(1, -1) * x * y, y ** 2 + oneof(1, -1) * x * y)
        point = (0, 0)
        answer = None
        func = numer / denom

        return locals()

    @classmethod
    def opt3(cls):
        # Limite existe: fatoração de produtos notáveis
        numb = oneof(-1, 1) * oneof(1, 2, 3, 4, 5, 6)
        func = (x ** 2 - y ** 2) / (abs(numb) * (x ** 3 - y ** 3) / 3)
        point = (numb, numb)
        answer = abs(numb)

        return locals()

    @classmethod
    def opt4(cls):
        # Limite não existe: teste por curva polinomial
        numb = oneof(-1, 1) * oneof(1, 2, 3, 4, 5, 6) * One
        func = (abs(numb) / 3) * (x ** 3 - y ** 3) / (x ** 2 - y ** 2)
        point = (numb, numb)
        answer = None

        return locals()

    @classmethod
    def opt5(cls):
        # Limite existe: composição de funções
        g = oneof(x * y, x + y - 1, x ** 2 + y ** 2 - 1)
        numb = oneof(2, 3, 4, 5, 6)
        func = ((1 + g) ** numb - 1) / g
        point = (0, 0)
        answer = numb

        assert func != 1
        return locals()

    @classmethod
    def opt6(cls):
        # Limite existe: coordenadas polares
        g = Lambda(x, log(x, 2))
        n = One * oneof(0, 1, 2, 3)
        a = Two ** n
        c = oneof(0, 1, 2, 3, 4)
        b = oneof(-1, 1) * oneof(1, 2, 3)
        func = g((a * x ** 2 + a * y ** 2 + b * x ** c * y ** (4 - c)) / (x ** 2 + y ** 2))
        point = (0, 0)
        answer = n

        return locals()

    @classmethod
    def opt7(cls):
        # Limite não existe: funções independentes, uma das quais não possui 
        # limite
        vars = [x, y]; shuffle(vars)
        u, v = vars

        g = oneof(sin(u) / u, tan(u) / u, (1 - cos(u)) / u ** 2)
        h = abs(v)
        func = g * h
        point = (0, 0)
        answer = None

        return locals()

# Entradas
opt = oneof(*[ o for o in dir(Opts) if o.startswith('opt') ])
niter = 0
with display_block('Entradas'):
    while True:
        niter += 1
        try:
            vars = getattr(Opts, opt)()
        except AssertionError:
            continue
        func = vars['func']
        point = vars['point']
        answer = vars['answer']
        vars = tuple(var(x) for (x, c) in zip('xyzw', point))
        break

# Salva resposta
g0, g1, g2, g3, g4, g5, g6, g7 = [0] * 8
if answer is None:
    g7 = 1
else:
    locals()['g%s' % answer] = 1
    assert (answer in range(7))
    assert 1 in [ g0, g1, g2, g3, g4, g5, g6, g7 ]

# Mostra resultados
with display_block('Resultados'):
    answers = list(enumerate([ g0, g1, g2, g3, g4, g5, g6, g7 ]))

